iT邦幫忙

2023 iThome 鐵人賽

DAY 26
0
Mobile Development

初窺Flutter系列 第 26

Flutter-動畫-頁面切換動畫&Hero動畫

  • 分享至 

  • xImage
  •  

頁面切換動畫最常使用的模式有
1.Hero動畫:使兩個頁面之間的共享widgets平滑切換的方式
2.自訂義轉場動畫:如果不滿意預設的轉場效果。可以使用PageRouteBuilder,自訂義轉場動畫

我們會先創建兩個頁面並寫入調轉頁面的觸發動作

創建第一頁

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('頁面跳轉動畫page1'),
      ),
      body: GestureDetector(
        child: Hero(
          tag: 'First photo', // Hero動畫的標籤,兩個頁面共享相同的標籤
          child: Image.network('https://stickershop.line-scdn.net/stickershop/v1/product/1427855/LINEStorePC/main.png?v=1'),
        ),
        //點擊圖片觸發跳轉下頁的指令
        onTap: () {
          Navigator.of(context).push(MaterialPageRoute(
            builder: (context) => SecondPage(),
          ));
        },
      ),
    );
  }
}

創建第二頁

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('頁面跳轉動畫page2'),
      ),
      body: GestureDetector(
        child: Hero(
          tag: 'Second photo', // 與第一頁相同的Hero標籤
          child: Image.network('https://img.lovepik.com/free-png/20210919/lovepik-goodbye-and-bye-bye-to-cartoon-facial-pack-png-image_400963701_wh1200.png'),
        ),
        onTap: () {
          Navigator.of(context).push(MaterialPageRoute(
            builder: (context) => FirstPage(), // 點擊圖片返回第一頁
          ));
        },
      ),
    );
  }
}

如果想要自訂義轉場動畫的時候,就要用到PageRouteBuilder的方法了!
這便是設定成平移動畫切換
這邊簡單更改上面程式碼中onTap: ()的部分

onTap: () {
          Navigator.of(context).push(PageRouteBuilder(
            pageBuilder: (context, animation, secondaryAnimation) {
              return FirstPage(); // 返回第一頁
            },
            //自定義頁面切換時的動畫效果
            transitionsBuilder: (context, animation, secondaryAnimation, child) {
              const begin = Offset(-1.0, 0.0); // 起始位置
              const end = Offset.zero; // 終點位置
              const curve = Curves.ease; // 動畫曲线
              
              // 創建一個tween,定義起始和終點位置
              var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
              //將tween應用到animation對象上,獲得一個位移動畫
              var offsetAnimation = animation.drive(tween);

              return SlideTransition(
                position: offsetAnimation, // 使用平移动画
                child: child,
              );
            },
          ));
        },

並在main方法中設定應用程式主題為自定義的頁面切換動畫主題

void main() {
  runApp(MaterialApp(
    home: FirstPage(),
    theme: ThemeData(
      pageTransitionsTheme: PageTransitionsTheme(
        builders: {
          TargetPlatform.android: OpenUpwardsPageTransitionsBuilder(),
        },
      ),
    ),
  ));
}


完整程式碼

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    home: FirstPage(),
    theme: ThemeData(
      pageTransitionsTheme: PageTransitionsTheme(
        builders: {
          TargetPlatform.android: OpenUpwardsPageTransitionsBuilder(),
        },
      ),
    ),
  ));
}

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('頁面跳轉動畫page1'),
      ),
      body: GestureDetector(
        child: Hero(
          tag: 'First photo',
          child: Image.network(
              'https://stickershop.line-scdn.net/stickershop/v1/product/1427855/LINEStorePC/main.png?v=1'),
        ),
        onTap: () {
          Navigator.of(context).push(PageRouteBuilder(
            pageBuilder: (context, animation, secondaryAnimation) {
              return SecondPage();
            },
            transitionsBuilder: (context, animation, secondaryAnimation, child) {
              const begin = Offset(1.0, 0.0);
              const end = Offset.zero;
              const curve = Curves.ease;

              var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
              var offsetAnimation = animation.drive(tween);

              return SlideTransition(
                position: offsetAnimation,
                child: child,
              );
            },
          ));
        },
      ),
    );
  }
}

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('頁面跳轉動畫page2'),
      ),
      body: GestureDetector(
        child: Hero(
          tag: 'Second photo',
          child: Image.network(
              'https://img.lovepik.com/free-png/20210919/lovepik-goodbye-and-bye-bye-to-cartoon-facial-pack-png-image_400963701_wh1200.png'),
        ),
        onTap: () {
          Navigator.of(context).push(PageRouteBuilder(
            pageBuilder: (context, animation, secondaryAnimation) {
              return FirstPage(); // 返回第一頁
            },
            transitionsBuilder: (context, animation, secondaryAnimation, child) {
              const begin = Offset(-1.0, 0.0);
              const end = Offset.zero;
              const curve = Curves.ease;

              var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
              var offsetAnimation = animation.drive(tween);

              return SlideTransition(
                position: offsetAnimation,
                child: child,
              );
            },
          ));
        },
      ),
    );
  }
}

成果展示
https://imgur.com/a/9ts9F4E


上一篇
Flutter-動畫-類物理特性的動畫
下一篇
Flutter動畫-交錯動畫
系列文
初窺Flutter30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言